Portfolio performance and key metrics¶
Code written by Vala "Valatility" Zeinali and Lev "l3v" Thierbach¶
In [1]:
import yfinance as yf
import numpy as np
import pandas as pd
from pandas_datareader import data as pdr
from matplotlib import pyplot as plt
import plotly.graph_objects as go
import warnings
import statistics as stats
import empyrical as emp
warnings.filterwarnings("ignore")
In [2]:
start_date = "2023-01-05"
end_date = "2023-12-12"
In [3]:
tickers = ["ARGT","AVTR","HCC","DHR","TMF","VZ","USO","TTWO","SHY","MBB","GLD","EWZ","EA","CTLT","GEHC","SPY"]
In [4]:
wts = [
-0.07
,-0.01
,0.03
,0.01
,0.24
,0.02
,0.23
,0.01
,0.10
,0.13
,-0.07
,0.07
,-0.01
,0.01
,0.03
,0.000
]
In [5]:
yf.pdr_override()
price_data = pdr.get_data_yahoo(tickers,
start = start_date,
end = end_date)
[*********************100%%**********************] 16 of 16 completed
In [6]:
price_data = price_data['Adj Close']
In [7]:
ret_data = price_data.pct_change()[1:]
In [8]:
weighted_returns = (wts * ret_data)
In [9]:
weighted_returns = weighted_returns.reset_index()
weighted_returns.head()
Out[9]:
| Date | ARGT | AVTR | CTLT | DHR | EA | EWZ | GEHC | GLD | HCC | MBB | SHY | SPY | TMF | TTWO | USO | VZ | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2023-01-06 | -0.001979 | 0.000276 | 0.000968 | -0.000107 | -0.001521 | 0.000771 | -0.000195 | 0.000187 | 0.003746 | 0.001680 | -0.000267 | 0.001605 | -0.000543 | -0.000114 | 0.000023 | 0.0 |
| 1 | 2023-01-09 | -0.001120 | -0.000294 | 0.000327 | 0.000101 | 0.000542 | -0.000148 | -0.003316 | 0.000022 | -0.002917 | 0.000384 | -0.000069 | -0.000040 | -0.000146 | 0.000033 | 0.000486 | -0.0 |
| 2 | 2023-01-10 | -0.000445 | -0.000392 | -0.000050 | 0.000464 | -0.000290 | 0.000520 | 0.007522 | 0.000037 | 0.001131 | -0.000533 | 0.000060 | 0.000491 | 0.000475 | 0.000041 | 0.000009 | 0.0 |
| 3 | 2023-01-11 | -0.001537 | -0.000331 | 0.000848 | 0.000259 | 0.004045 | 0.000458 | 0.019128 | -0.000007 | 0.000206 | 0.000906 | -0.000060 | 0.000885 | -0.000463 | -0.000026 | 0.000979 | -0.0 |
| 4 | 2023-01-12 | -0.002049 | 0.000023 | -0.000067 | -0.000055 | 0.000590 | 0.000170 | 0.002336 | 0.000116 | -0.000675 | 0.000913 | -0.000154 | 0.000255 | -0.000576 | -0.000092 | 0.000247 | 0.0 |
In [10]:
# Calculate portfolio returns
port_ret = weighted_returns.drop("Date", axis=1).sum(axis=1)
# axis =1 tells pandas we want to add
In [11]:
cumulative_ret = ((port_ret + 1).cumprod()) - 1
cumulative_ret_single_tick = (((ret_data + 1).cumprod()) - 1)*100
In [12]:
MHF = cumulative_ret
SPY = ((ret_data["SPY"] + 1).cumprod()) - 1
In [13]:
fig1 = go.Figure() # go object
fig1.add_trace(go.Scatter(x=weighted_returns["Date"],y=MHF*100, name='Valatility Return',
line=dict(color='royalblue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=SPY*100, name='SPY',
line=dict(color='green', width=3,)))
# Edit the layout
fig1.update_layout(title=f'Mock Hedgefund {(MHF.tail(1).values *100).round(2)}% vs SPY {(SPY.tail(1).values *100).round(2)}% - 2023',
xaxis_title='Year',
yaxis_title='Cumulative Return (%)', width=1000, height=800,)
fig1.show()
In [14]:
fig1 = go.Figure() # go object
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['ARGT'], name='ARGT',
line=dict(color='green', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['AVTR'], name='AVTR',
line=dict(color='red', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['HCC'], name='HCC',
line=dict(color='blue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['DHR'], name='DHR',
line=dict(color='brown', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['TMF'], name='TMF',
line=dict(color='yellow', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['VZ'], name='VZ',
line=dict(color='orange', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['USO'], name='USO',
line=dict(color='pink', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['TTWO'], name='TTWO',
line=dict(color='purple', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['SHY'], name='SHY',
line=dict(color='black', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['MBB'], name='MBB',
line=dict(color='tan', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['GLD'], name='GLD',
line=dict(color='goldenrod', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['EWZ'], name='EWZ',
line=dict(color='magenta', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['EA'], name='EA',
line=dict(color='darkturquoise', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['CTLT'], name='CTLT',
line=dict(color='aquamarine', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['GEHC'], name='GEHC',
line=dict(color='aquamarine', width=3,)))
fig1.update_layout(title=f'Time series of all assets| Cumulative Return - 2023 (%)',
xaxis_title='Year',
yaxis_title='Cumulative Return)(%)', width=1000, height=800,)
fig1.show()
In [15]:
Alpha = (MHF.tail(1).values *100).round(2) - (SPY.tail(1).values *100).round(2)
In [16]:
Beta = stats.covariance(MHF, SPY) / stats.variance(SPY)
In [17]:
# Calculate the Sharpe Ratio
sharpe_ratio = np.mean(MHF) / np.std(MHF)
# Annualize the Sharpe Ratio
annual_factor = np.sqrt(252) # Use 252 for daily returns, 52 for weekly returns, 12 for monthly returns
sharpe_ratio_annu = sharpe_ratio * annual_factor
Alpha for all assets
In [18]:
alpha_values = []
asset_names = []
# Calculate Alpha for each asset
for asset in tickers:
asset_returns = ret_data[asset]
risk_free_rate = 0.00
excess_return = asset_returns - risk_free_rate
alpha = (excess_return.mean() * 252) * 100 # % Annualized Alpha
asset_names.append(asset)
alpha_values.append(alpha)
# Create a df to hold Asset and Alpha values
alpha_df = pd.DataFrame({'Asset': asset_names, 'Alpha': alpha_values})
Beta for all assets
In [19]:
beta_values = []
# Calculate Beta for each asset
for asset in tickers:
asset_returns = ret_data[asset]
covar = stats.covariance(asset_returns, SPY)
var = stats.variance(SPY)
beta = covar / var
beta_values.append(beta)
# Create a df to hold Asset and Beta values
beta_df = pd.DataFrame({'Asset': tickers, 'Beta': beta_values})
Plot Alpha
In [20]:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=alpha_values, y=asset_names,
name='Alpha',
mode='markers',
marker_color= alpha_values
)
)
fig.update_layout(title='Alpha| Asset vs. Benchmark(SPY) for Portfolio Assets - 2023',
yaxis_title='Ticker', width=1000, height=800,
xaxis_title='Alpha Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
Plot Beta
In [21]:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=beta_values, y=tickers,
name='Beta',
mode='markers',
marker_color= beta_values
)
)
fig.update_layout(title='Beta| Asset vs. Benchmark(SPY) for Portfolio Assets - 2023',
yaxis_title='Ticker', width=1000, height=800,
xaxis_title='Beta Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
Metrics
In [22]:
print(f'Annualized Sharpe Ratio (2023): {round(sharpe_ratio_annu, 2)}%')
Annualized Sharpe Ratio (2023): 42.58%
In [23]:
print(f'2023 Yearly Alpha: {round(Alpha[0], 2)}%')
2023 Yearly Alpha: -7.54%
In [24]:
print(f'2023 Yearly Beta: {round(Beta, 2)}')
2023 Yearly Beta: 0.35
Equities¶
In [25]:
eqticks = ["AVTR","HCC","VZ","TTWO","EA","CTLT","GEHC","SPY"]
In [26]:
yf.pdr_override()
price_data_eq1 = pdr.get_data_yahoo(eqticks,
start = start_date,
end = end_date)
[*********************100%%**********************] 8 of 8 completed
In [27]:
price_data_eq = price_data_eq1['Adj Close']
In [28]:
wts_eq = [
-0.01
,0.3
,0.02
,0.01
,-0.01
,0.01
,0.03
,0.000
]
In [29]:
ret_data_eq = price_data_eq.pct_change()[1:]
In [30]:
weighted_returns_eq = (wts_eq * ret_data_eq)
In [31]:
weighted_returns_eq = weighted_returns_eq.reset_index()
In [32]:
# Calculate portfolio equities returns
port_ret_eq = weighted_returns_eq.drop("Date", axis=1).sum(axis=1)
In [33]:
cumulative_ret_eq = ((port_ret_eq + 1).cumprod()) - 1
cumulative_ret_single_tick_eq = (((ret_data_eq + 1).cumprod()) - 1)*100
In [34]:
MHF_EQ = cumulative_ret_eq
In [35]:
fig1 = go.Figure() # go object
fig1.add_trace(go.Scatter(x=weighted_returns_eq["Date"],y=MHF_EQ*100, name='Equites Return',
line=dict(color='royalblue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=SPY*100, name='SPY',
line=dict(color='green', width=3,)))
# Edit the layout
fig1.update_layout(title=f'Mock Hedge fund| Equities {(MHF_EQ.tail(1).values *100).round(2)}% vs SPY {(SPY.tail(1).values *100).round(2)}% - 2023',
xaxis_title='Year',
yaxis_title='Cumulative Return (%)', width=1000, height=800,)
fig1.show()
In [36]:
fig1 = go.Figure() # go object
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['AVTR'], name='AVTR',
line=dict(color='green', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['HCC'], name='HCC',
line=dict(color='red', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['VZ'], name='VT',
line=dict(color='blue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['TTWO'], name='TTWO',
line=dict(color='brown', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['EA'], name='EA',
line=dict(color='yellow', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['CTLT'], name='CTLT',
line=dict(color='orange', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['GEHC'], name='GEHC',
line=dict(color='orange', width=3,)))
fig1.update_layout(title=f'Time series of Equties| Cumulative Return - 2023 (%)',
xaxis_title='Year',
yaxis_title='Cumulative Return)(%)', width=1000, height=800,)
fig1.show()
In [37]:
Alpha_EQ = (MHF_EQ.tail(1).values *100).round(2) - (SPY.tail(1).values *100).round(2)
In [38]:
Beta_EQ = stats.covariance(MHF_EQ, SPY) / stats.variance(SPY)
In [39]:
# Calculate the Sharpe Ratio for EQ
sharpe_ratio_EQ = np.mean(MHF_EQ) / np.std(MHF_EQ)
# Annualize the Sharpe
annual_factor_EQ = np.sqrt(252)
sharpe_ratio_annu_EQ = sharpe_ratio_EQ * annual_factor_EQ
In [40]:
alpha_values_eq = []
asset_names_eq = []
# Calculate Alpha for each equitie
for asset_eq in eqticks:
asset_returns_eq = ret_data_eq[asset_eq]
risk_free_rate = 0.00
excess_return_eq = asset_returns_eq - risk_free_rate
alpha_eq = (excess_return_eq.mean() * 252) * 100 # % Annualized Alpha
asset_names_eq.append(asset_eq)
alpha_values_eq.append(alpha_eq)
# Create a df to hold Asset names and Alpha values
alpha_df_eq = pd.DataFrame({'Asset': asset_names_eq, 'Alpha': alpha_values_eq})
In [41]:
beta_values_eq = []
# Calculate Beta for each asset
for asset_eq in eqticks:
asset_returns_eq = ret_data_eq[asset_eq]
covar_eq = stats.covariance(asset_returns_eq, SPY)
var_eq = stats.variance(SPY)
beta_eq = covar_eq / var_eq
beta_values_eq.append(beta_eq)
# Create a df to hold Asset and Beta values
beta_df_eq = pd.DataFrame({'Asset': eqticks, 'Beta': beta_values_eq})
In [42]:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=alpha_values_eq, y=asset_names_eq,
name='Alpha',
mode='markers',
marker_color= alpha_values_eq
)
)
fig.update_layout(title='Alpha| Equities vs. Benchmark(SPY) for Portfolio Assets - 2023',
yaxis_title='Ticker', width=1000, height=800,
xaxis_title='Alpha Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
In [43]:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=beta_values_eq, y=eqticks,
name='Beta',
mode='markers',
marker_color= beta_values_eq
)
)
fig.update_layout(title='Beta| Equities vs. Benchmark(SPY) for Portfolio Assets - 2023',
yaxis_title='Ticker', width=1000, height=800,
xaxis_title='Beta Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
In [44]:
print(f'Annualized Equities Sharpe Ratio (2023): {round(sharpe_ratio_annu_EQ, 2)}%')
Annualized Equities Sharpe Ratio (2023): 16.62%
In [45]:
print(f'2023 Yearly Equities Alpha: {round(Alpha_EQ[0], 2)}%')
2023 Yearly Equities Alpha: -10.69%
In [46]:
print(f'2023 Yearly Equities Beta: {round(Beta_EQ, 2)}')
2023 Yearly Equities Beta: -0.24
Global Macro¶
In [47]:
tickers_gm = ["ARGT","TMF","USO","SHY","MBB","GLD","EWZ","SPY"]
In [48]:
wts_gm = [
-0.07
,0.24
,-0.23
,0.10
,0.13
,-0.07
,0.07
,0.000
]
In [49]:
yf.pdr_override()
price_data_gm1 = pdr.get_data_yahoo(tickers_gm,
start = start_date,
end = end_date)
[*********************100%%**********************] 8 of 8 completed
In [50]:
price_data_gm = price_data_gm1['Adj Close']
In [51]:
ret_data_gm = price_data_gm.pct_change()[1:]
In [52]:
weighted_returns_gm = (wts_gm * ret_data_gm)
In [53]:
weighted_returns_gm = weighted_returns_gm.reset_index()
In [54]:
# Calculate portfolio macro returns
port_ret_gm = weighted_returns_gm.drop("Date", axis=1).sum(axis=1)
In [55]:
cumulative_ret_gm = ((port_ret_gm + 1).cumprod()) - 1
cumulative_ret_single_tick_gm = (((ret_data_gm + 1).cumprod()) - 1)*100
In [56]:
MHF_GM = cumulative_ret_gm
In [57]:
fig1 = go.Figure() # go object
fig1.add_trace(go.Scatter(x=weighted_returns_gm["Date"],y=MHF_GM*100, name='Macro Return',
line=dict(color='royalblue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=SPY*100, name='SPY',
line=dict(color='green', width=3,)))
# Edit the layout
fig1.update_layout(title=f'Mock Hedge fund| Global Macro {(MHF_GM.tail(1).values *100).round(2)}% vs SPY {(SPY.tail(1).values *100).round(2)}% - 2023',
xaxis_title='Year',
yaxis_title='Cumulative Return (%)', width=1000, height=800,)
fig1.show()
In [58]:
fig1 = go.Figure() # go object
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['ARGT'], name='ARGT',
line=dict(color='green', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['TMF'], name='TMF',
line=dict(color='red', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['USO'], name='USO',
line=dict(color='blue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['SHY'], name='SHY',
line=dict(color='brown', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['MBB'], name='MBB',
line=dict(color='yellow', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['GLD'], name='GLD',
line=dict(color='orange', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['EWZ'], name='EWZ',
line=dict(color='orange', width=3,)))
fig1.update_layout(title=f'Time series of Global Macro| Cumulative Return - 2023 (%)',
xaxis_title='Year',
yaxis_title='Cumulative Return)(%)', width=1000, height=800,)
fig1.show()
In [59]:
Alpha_GM = (MHF_GM.tail(1).values *100).round(2) - (SPY.tail(1).values *100).round(2)
In [60]:
Beta_GM = stats.covariance(MHF_GM, SPY) / stats.variance(SPY)
In [61]:
# Calculate the Sharpe Ratio for Macro
sharpe_ratio_GM = np.mean(MHF_GM) / np.std(MHF_GM)
# Annualize the Sharpe
annual_factor_GM = np.sqrt(252)
sharpe_ratio_annu_GM = sharpe_ratio_GM * annual_factor_GM
In [62]:
alpha_values_gm = []
asset_names_gm = []
# Calculate Alpha for each equitie
for asset_gm in tickers_gm:
asset_returns_gm = ret_data_gm[asset_gm]
risk_free_rate = 0.00
excess_return_gm = asset_returns_gm - risk_free_rate
alpha_gm = (excess_return_gm.mean() * 252) * 100 # % Annualized Alpha
asset_names_gm.append(asset_gm)
alpha_values_gm.append(alpha_gm)
# Create a df to hold Asset names and Alpha values
alpha_df_gm = pd.DataFrame({'Asset': asset_names_gm, 'Alpha': alpha_values_gm})
In [63]:
beta_values_gm = []
# Calculate Beta for each asset
for asset_gm in tickers_gm:
asset_returns_gm = ret_data_gm[asset_gm]
covar_gm = stats.covariance(asset_returns_gm, SPY)
var_gm = stats.variance(SPY)
beta_gm = covar_gm / var_gm
beta_values_gm.append(beta_gm)
# Create a df to hold Asset and Beta values
beta_df_gm = pd.DataFrame({'Asset': tickers_gm, 'Beta': beta_values_gm})
In [64]:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=alpha_values_gm, y=asset_names_gm,
name='Alpha',
mode='markers',
marker_color= alpha_values_gm
)
)
fig.update_layout(title='Alpha| Global Macro vs. Benchmark(SPY) for Portfolio Assets - 2023',
yaxis_title='Ticker', width=1000, height=800,
xaxis_title='Alpha Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
In [65]:
fig = go.Figure()
fig.add_trace(go.Scatter(
x=beta_values_gm, y=tickers_gm,
name='Beta',
mode='markers',
marker_color= beta_values_gm
)
)
fig.update_layout(title='Beta| Equities vs. Benchmark(SPY) for Portfolio Assets - 2023',
yaxis_title='Ticker', width=1000, height=800,
xaxis_title='Beta Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
In [66]:
print(f'Annualized Global Macro Sharpe Ratio (2023): {round(sharpe_ratio_annu_GM, 2)}%')
Annualized Global Macro Sharpe Ratio (2023): -12.85%
In [67]:
print(f'2023 Yearly Global Macro Alpha: {round(Alpha_GM[0], 2)}%')
2023 Yearly Global Macro Alpha: -16.83%
In [68]:
print(f'2023 Yearly Global Macro Beta: {round(Beta_GM, 2)}')
2023 Yearly Global Macro Beta: 0.02